
#include "SB.h"
#include "ParticleManager.h"
#include "TextureManager.h"
#include <libXml/tree.h>
#include "XMLController.h"
#include "Painter.h"

extern "C" const char* getFilePath(const char* fileName);

ParticleManager::~ParticleManager()
{
    std::vector<ParticleSystem*>::iterator it = particleSystems.begin();
	while(it != particleSystems.end())
	{
		delete (*it);
		++it;
	}
	particleSystems.clear();
    
	baseParticleSystems.clear();
}

void ParticleManager::initialize()
{
}

void ParticleManager::loadContent()
{
	
}

void ParticleManager::loadXML()
{
	baseParticleSystems.clear();
    
    xmlDocPtr doc = NULL;
    std::string fileName = "/particles.xml";
    std::string fullName = getFilePath(fileName.c_str());
    doc = xmlReadFile(fullName.c_str(), "UTF8", 0);
	if (doc == NULL) {
		return;        
	}

	xmlNode *root = NULL;
	root = xmlDocGetRootElement(doc);
    
	std::string systemName;
    
    xmlNode* nodeParticleSystem = root->children;
    while(nodeParticleSystem)
    {
        if(nodeParticleSystem->type != XML_ELEMENT_NODE)
        {
            nodeParticleSystem = nodeParticleSystem->next;
            continue;
        }
        
        systemName = (const char*) xmlGetProp(nodeParticleSystem, (xmlChar*)"name");
        ParticleSystemData data;
        
		data.name = systemName;
		std::string strType = (const char*) xmlGetProp(nodeParticleSystem, (xmlChar*)"type");
		if (strcmp(strType.c_str(), "fountain") == 0)
		{
			data.type = Fountain;
		}
		else if (strcmp(strType.c_str(), "burst") == 0)
		{
			data.type = Burst;
		}
        data.textureName = XMLController::getString( nodeParticleSystem, "textureName");
        strType = (const char*) xmlGetProp(nodeParticleSystem, (xmlChar*)"additive");
		data.bAdditive = strcmp(strType.c_str(), "true") == 0;

        data.texture = (Texture*) TextureManager::instance().getTextureByName("/" + data.textureName);
		data.nParticles = XMLController::getInt( nodeParticleSystem, "nParticles");
        data.systemLife = XMLController::getFloat( nodeParticleSystem, "systemLife");
		XMLController::parseVector3(XMLController::getString( nodeParticleSystem, "position"), data.position);
		XMLController::parseVector3(XMLController::getString( nodeParticleSystem, "direction"), data.direction);
		XMLController::parseVector3(XMLController::getString( nodeParticleSystem, "acceleration"), data.acceleration);
		XMLController::parseVector3(XMLController::getString( nodeParticleSystem, "positionVarianceMin"), data.positionVarianceMin);
		XMLController::parseVector3(XMLController::getString( nodeParticleSystem, "directionVarianceMin"), data.directionVarianceMin);
		XMLController::parseVector3(XMLController::getString( nodeParticleSystem, "accelerationVarianceMin"), data.accelerationVarianceMin);
		XMLController::parseVector3(XMLController::getString( nodeParticleSystem, "positionVarianceMax"), data.positionVarianceMax);
		XMLController::parseVector3(XMLController::getString( nodeParticleSystem, "directionVarianceMax"), data.directionVarianceMax);
		XMLController::parseVector3(XMLController::getString( nodeParticleSystem, "accelerationVarianceMax"), data.accelerationVarianceMax);
		XMLController::parseVector4(XMLController::getString( nodeParticleSystem, "color"), data.color);
		XMLController::parseVector4(XMLController::getString( nodeParticleSystem, "colorVarianceMin"), data.colorVarianceMin);
		XMLController::parseVector4(XMLController::getString( nodeParticleSystem, "colorVarianceMax"), data.colorVarianceMax);
        
        float f = 1.0f/255.0f;
        data.color *= f;
        data.colorVarianceMin *= f;
        data.colorVarianceMax *= f;
        
        data.particlesRotation = XMLController::getFloat( nodeParticleSystem, "particlesRotation");
        data.particlesRotationSpeed = XMLController::getFloat( nodeParticleSystem, "particlesRotationSpeed");
        data.particlesRotationVariance = XMLController::getFloat( nodeParticleSystem, "particlesRotationVariance");
        data.particlesRotationSpeedVariance = XMLController::getFloat( nodeParticleSystem, "particlesRotationSpeedVariance");
        data.size = XMLController::getFloat( nodeParticleSystem, "size");
        data.sizeIni = XMLController::getFloat( nodeParticleSystem, "sizeIni");
        data.sizeEnd = XMLController::getFloat( nodeParticleSystem, "sizeEnd");
        data.fadeIn = XMLController::getFloat( nodeParticleSystem, "fadeIn");
        data.fadeOut = XMLController::getFloat( nodeParticleSystem, "fadeOut");
        data.particlesLife = XMLController::getFloat( nodeParticleSystem, "particlesLife");        
        
		baseParticleSystems.insert(std::pair<std::string, ParticleSystemData>(systemName, data));
        
        nodeParticleSystem = nodeParticleSystem->next;
//		SB::ownAssert(info.fadeIn + info.fadeOut <= info.particlesLife);
//		SB::ownAssert(info.positionVarianceMin.x <= info.positionVarianceMax.x);
//		SB::ownAssert(info.positionVarianceMin.y <= info.positionVarianceMax.y);
//		SB::ownAssert(info.positionVarianceMin.z <= info.positionVarianceMax.z);
//		SB::ownAssert(info.directionVarianceMin.x <= info.directionVarianceMax.x);
//		SB::ownAssert(info.directionVarianceMin.y <= info.directionVarianceMax.y);
//		SB::ownAssert(info.directionVarianceMin.z <= info.directionVarianceMax.z);
//		SB::ownAssert(info.accelerationVarianceMin.x <= info.accelerationVarianceMax.x);
//		SB::ownAssert(info.accelerationVarianceMin.y <= info.accelerationVarianceMax.y);
//		SB::ownAssert(info.accelerationVarianceMin.z <= info.accelerationVarianceMax.z);
	}
}

void ParticleManager::resetParticleSystems()
{
	std::vector<ParticleSystem*>::iterator it = particleSystems.begin();
	while(particleSystems.end() != it)
	{
		(*it)->initialize((*it)->info.name.c_str(), (*it)->position, (*it)->customDirection);
		it++;
	}
}
void ParticleManager::update()
{
    std::vector<ParticleSystem*>::iterator it;
    for ( it = particleSystems.begin(); it != particleSystems.end(); )
    {
        if( (*it)->isDead )
        {
            delete * it;  
            it = particleSystems.erase(it);
        }
        else
        {
            (*it)->update();
            ++it;
        }
    }
}

void ParticleManager::render()
{   
    bool bAdditive = false;
    
	std::vector<ParticleSystem*>::iterator it = particleSystems.begin();
	while(particleSystems.end() != it)
	{
        if ((*it)->m_bRender)
        {
            if ((*it)->info.bAdditive && !bAdditive)
            {
                glBlendFunc(GL_SRC_ALPHA, GL_ONE);
                bAdditive = true;
            }
            else if (!(*it)->info.bAdditive && bAdditive)
            {
                glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
                bAdditive = false;
            }
            Particles particles = (*it)->particles;
            Particles::iterator it2 = particles.begin();
            while(particles.end() != it2)
            {
                Painter::drawTexturedQad(it2->position.x, it2->position.y, 0.5f, 0.5f, (*it)->info.texture->getSize().x * 0.5f * it2->size, (*it)->info.texture->getSize().y * 0.5f * it2->size, 0, 0, 1, 1, it2->rotation, (*it)->info.texture, Vector4(it2->color[0], it2->color[1], it2->color[2], it2->color[3]));
                it2++;
            }
        }
        it++;
	}
    
    if(bAdditive)
        glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
}

ParticleSystem* ParticleManager::addParticles(const char* name, const Vector3 &position, const Vector3 &direction)
{
	ParticleSystem* ps = new ParticleSystem();
	ps->initialize(name, position, direction);
	particleSystems.push_back(ps);
    return ps;
}
